package com.tmt.im.manager.service;

import com.alibaba.fastjson2.JSONObject;
import com.tmt.data.jpa.enums.SMSCodeType;
import com.tmt.data.jpa.interfaces.ISMSCodeStorage;
import com.tmt.data.jpa.service.TmtJpaDataService;
import com.tmt.data.jpa.service.beans.LoadNewUserResponse;
import com.tmt.data.jpa.service.beans.UserInfoVo;
import com.tmt.im.common.enums.AddFriendMode;
import com.tmt.im.common.enums.IMRoleEnum;
import com.tmt.im.common.pojo.IMUserPoJo;
import com.tmt.im.common.pojo.PersonalSettingPoJo;
import com.tmt.im.jpa.entity.*;
import com.tmt.im.jpa.repository.IMUserRepo;
import com.tmt.im.jpa.repository.IMUserRoleRepo;
import com.tmt.im.jpa.repository.SystemParamRepo;
import com.tmt.im.manager.config.beans.CurrentServiceProperties;
import com.tmt.im.manager.config.beans.DataSyncProperties;
import com.tmt.im.manager.controller.api.FileController;
import com.tmt.im.manager.controller.vo.*;
import com.tmt.im.manager.helper.IgniteQueryHelper;
import com.tmt.im.manager.helper.PrincipalHelper;
import com.tmt.im.manager.helper.QrCodeHelper;
import com.tmt.im.manager.interfaces.IYunXinInterface;
import com.tmt.im.manager.mapstruct.IMUserMapStruct;
import com.tmt.springboot.common.annotation._JsonBinding;
import com.tmt.springboot.common.helper.IdSnowFlake;
import com.tmt.springboot.common.restful.ExecuteResult;
import com.tmt.springboot.common.restful.IExecuteResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Field;
import java.security.Principal;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/8/5 10:14
 * @Version 1.0
 **/
@Slf4j
@Service
@Order(1)
public class IMUserService extends TmtJpaDataService<IMUser, Long> {

    private final ApplicationContext applicationContext;

    private final IMUserRepo imUserRepo;

    private final SystemParamRepo paramRepo;

    private final IMUserMapStruct imUserMapStruct;

    private final String clientId;

    private final Ignite ignite;

    private final String apiUrlPrefix;

    private final DataSyncProperties dataSyncProperties;

    private final IYunXinInterface iYunXinInterface;

    private String avatarUrlPrefix;

    private final ISMSCodeStorage ismsCodeStorage;

    private final CurrentServiceProperties serviceProperties;

    private final IMUserRoleRepo userRoleRepo;

    public IMUserService(ApplicationContext applicationContext,
                         @Value("${client.clientId}")
                         String clientId,
                         @Value("${api-url-prefix}")
                         String apiUrlPrefix,
                         DataSyncProperties dataSyncProperties,
                         IMUserRepo mainRepo,
                         IMUserRoleRepo userRoleRepo,
                         SystemParamRepo paramRepo,
                         IMUserMapStruct imUserMapStruct,
                         Ignite ignite,
                         IYunXinInterface iYunXinInterface,
                         ISMSCodeStorage ismsCodeStorage,
                         CurrentServiceProperties serviceProperties) {
        super(mainRepo);
        this.applicationContext = applicationContext;
        this.imUserRepo = mainRepo;
        this.paramRepo = paramRepo;
        this.imUserMapStruct = imUserMapStruct;
        this.ignite = ignite;
        this.iYunXinInterface = iYunXinInterface;
        this.ismsCodeStorage = ismsCodeStorage;
        this.serviceProperties = serviceProperties;

        this.clientId = clientId;
        this.apiUrlPrefix = apiUrlPrefix;
        this.dataSyncProperties = dataSyncProperties;

        this.userRoleRepo = userRoleRepo;
    }

    @Transactional(rollbackFor = Exception.class)
    public void InitializeTable() {
        try {
            log.info("----从授权服务器拉取已经存在的用户列表----开始---");
            loadUserList(null);
            log.info("----从授权服务器拉取已经存在的用户列表----结束---");
        } catch (Exception ex) {
            log.debug(ex.getMessage(), ex);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public IExecuteResult<Boolean> loadUserList(Principal principal) {
        HttpHeaders headers = null;
        if (principal != null) {
            String tokenValue = null;
            if (principal instanceof BearerTokenAuthentication token) {
                tokenValue = token.getToken().getTokenValue();
            } else if (principal instanceof JwtAuthenticationToken token) {
                tokenValue = token.getToken().getTokenValue();
            }
            assert tokenValue != null;

            headers = new HttpHeaders();
            headers.setBearerAuth(tokenValue);
        }

        IMUser latestUser = imUserRepo.findFirstByOrderByIdDesc();
        Long latestId = latestUser != null ? latestUser.getId() : 0L;

        Timestamp updateTime = imUserRepo.queryMaxUpdateTime();

        long pageIndex = 0;
        Long totalPageCount = null;

        JSONObject request = new JSONObject();
        request.put("startId", latestId);
        request.put("updateTime", updateTime);
        request.put("pageIndex", pageIndex);
        request.put("pageSize", 50);
        request.put("clientId", clientId);

        while (totalPageCount == null || pageIndex < totalPageCount) {
            HttpEntity<Map<String, Object>> entity = (headers != null) ?
                    new HttpEntity<>(request, headers) : new HttpEntity<>(request);
            ParameterizedTypeReference<ExecuteResult<LoadNewUserResponse>> responseType = new ParameterizedTypeReference<>() {
            };
            ResponseEntity<ExecuteResult<LoadNewUserResponse>> jsonObjectResponseEntity =
                    new RestTemplate().exchange(dataSyncProperties.getUserDataUrl(), HttpMethod.POST, entity, responseType);

            ExecuteResult<LoadNewUserResponse> body = jsonObjectResponseEntity.getBody();
            assert body != null;
            if (body.getData() == null || CollectionUtils.isEmpty(body.getData().getUserInfoVos())) {
                return ExecuteResult.success(true);
            }
            try {
                for (UserInfoVo vo : body.getData().getUserInfoVos()) {
                    try {
                        if (imUserRepo.findById(vo.getId()).orElse(null) != null) {
                            updateUser(vo);
                        } else {
                            registerUser(vo);
                        }
                    } catch (Exception ex) {
                    }
                }
                if (totalPageCount == null) {
                    totalPageCount = body.getData().getTotalPages();
                }
                pageIndex++;
                request.put("pageIndex", pageIndex);
            } catch (Exception ex) {
                String info = MessageFormat.format("接口{0}返回的数据格式异常:{1}", dataSyncProperties.getUserDataUrl(), body);
                return ExecuteResult.failure(info, false);
            }
        }

        return ExecuteResult.success(true);
    }

    @Transactional(readOnly = true)
    public IExecuteResult<UserInfoVoEx> getUserInfoEx(Long userId, String deviceType, String deviceId) {
        IMUser imUser = imUserRepo.findById(userId).orElse(null);
        if (imUser != null) {
            SystemParam param = paramRepo.findOneByParamCode("enable_real_name_auth");
            if (param != null && "true".equalsIgnoreCase(param.getParamValue())) {
                if (!StringUtils.hasText(imUser.getCertNo()) || !StringUtils.hasText(imUser.getCertName())) {
                    return ExecuteResult.failure(777, "用户尚未完成实名认证", null);
                }
            }

            UserInfoVoEx ovEx = imUserMapStruct.toUserInfoVoEx(imUser);
            //username字段填充成昵称
            ovEx.setUsername(imUser.getNickname());

            String url = "http://" + serviceProperties.getExternalClientService() + QrCodeHelper.getQrCodeUrl(apiUrlPrefix, userId);
            ovEx.setQrCodeUrl(url);
            ovEx.setOffsiteLogin(imUser.getDeviceIds() != null && !imUser.getDeviceIds().contains(deviceId));
            if (StringUtils.hasText(ovEx.getAvatar())) {
                //构造完整的头像访问路径。
                url = "http://" + serviceProperties.getExternalClientService() + ovEx.getAvatar();
                ovEx.setAvatar(url);
            }
            return ExecuteResult.success(ovEx);
        }
        return ExecuteResult.failure("目标用户不存在", null);
    }

    @Transactional(rollbackFor = Exception.class)
    public IMUser registerUser(UserInfoVo vo) throws Exception {
        //如果客户ID参数不为空，且与本地客户ID不相等，则直接返回。
        if (vo.getClientId() != null && !clientId.equals(vo.getClientId())) {
            return null;
        }

        IMUser user = imUserRepo.findById(vo.getId()).orElse(null);
        if (user != null) {
            return user;
        }

        if (!StringUtils.hasText(avatarUrlPrefix)) {
            FileController controller = applicationContext.getBean(FileController.class);
            RequestMapping ann = null;
            if (controller.getClass().getSimpleName().endsWith(".FileController")) {
                ann = controller.getClass().getAnnotation(RequestMapping.class);
            } else {
                ann = ((Class<?>) controller.getClass().getGenericSuperclass()).getAnnotation(RequestMapping.class);
            }
            assert ann != null;
            avatarUrlPrefix = ann.value()[0].replace("${api-url-prefix}", apiUrlPrefix);
        }

        String avatarUrl = MessageFormat.format("{0}/avatar/user/{1}.png", avatarUrlPrefix, "" + vo.getId());
        avatarUrl = avatarUrl.replaceAll("//", "/");

        user = IMUser.builder()
                .id(vo.getId())
                .username(vo.getMobile())
                .nickname(vo.getNickname())
                .memberCode(RandomStringUtils.randomNumeric(9))
                .avatar(avatarUrl)
                .password(vo.getPassword())
                .mobile(vo.getMobile())
                .deviceType(vo.getDeviceType())
                .deviceIds(vo.getDeviceIds())
                .accountNonExpired(true)
                .accountNonLocked(true)
                .credentialsNonExpired(true)
                .grade(0)
                .enabled(true)
                .createTime(vo.getCreateTime() != null ? vo.getCreateTime() : new Timestamp(System.currentTimeMillis()))
                .updateTime(vo.getUpdateTime())
                .build();

        PersonalSetting setting = PersonalSetting.builder()
                .id(IdSnowFlake.getId())
                .owner(user)
                .reviewOnAddingFriend(true)
                .enableShockHint(true)
                .enableSoundHint(true)
                .enableNewMsgNotify(true)
                .enableAddFriend(true)
                .addFriendModes(Arrays.stream(AddFriendMode.values()).toList())
                .createTime(user.getCreateTime())
                .build();

        Wallet wallet = Wallet.builder()
                .id(IdSnowFlake.getId())
                .owner(user)
                .balance(0L)
                .password(null)
                .aliPay(null)
                .weiXin(null)
                .createTime(user.getCreateTime())
                .build();

        user.setSetting(setting);
        user.setSettingId(setting.getId());

        user.setWallet(wallet);
        user.setWalletId(wallet.getId());

        //向云信平台注册用户。
        StringBuilder error = new StringBuilder();
        if (!iYunXinInterface.registerUser(user, error)) {
            throw new Exception(error.toString());
        }
        //保存到数据库
        return imUserRepo.save(user);
    }

    public IExecuteResult<Boolean> updateUser(UserInfoVo vo) {
        //如果客户ID参数不为空，且与本地客户ID不相等，则直接返回。
        if (vo.getClientId() != null && !clientId.equals(vo.getClientId())) {
            return ExecuteResult.success(false);
        }

        IMUser user = imUserRepo.findById(vo.getId()).orElse(null);
        if (user == null) {
            return ExecuteResult.failure("用户不存在", false);
        }

        boolean needSyncYunXin = false;
        //只能修以下字段信息。
        if (StringUtils.hasText(vo.getUsername())
                && !vo.getUsername().equals(user.getUsername())) {
            user.setUsername(vo.getUsername());
        }
        if (StringUtils.hasText(vo.getNickname())
                && !vo.getNickname().equals(user.getNickname())) {
            user.setNickname(vo.getNickname());
            needSyncYunXin = true;
        }
        if (StringUtils.hasText(vo.getCertName())
                && !vo.getNickname().equals(user.getCertName())) {
            user.setCertName(vo.getCertName());
        }
        if (StringUtils.hasText(vo.getCertNo())
                && !vo.getNickname().equals(user.getCertNo())) {
            user.setCertNo(vo.getCertNo());
        }
        if (StringUtils.hasText(vo.getMobile())
                && !vo.getMobile().equals(user.getMobile())) {
            user.setMobile(vo.getMobile());
            needSyncYunXin = true;
        }
        if (StringUtils.hasText(vo.getPassword())
                && !vo.getPassword().equals(user.getPassword())) {
            user.setPassword(vo.getPassword());
        }
        if (vo.getUpdateTime() != null
                && vo.getUpdateTime() != user.getUpdateTime()) {
            user.setUpdateTime(vo.getUpdateTime());
        }

        if (needSyncYunXin) {
            //向云信平台同步数据。
            StringBuilder error = new StringBuilder();
            if (!iYunXinInterface.updateUserInfo(user, error)) {
                return ExecuteResult.failure(error.toString(), false);
            }
        }

        user = imUserRepo.save(user);

        IgniteCache<Long, IMUserPoJo> userCache = ignite.cache(IMUserPoJo.CACHE_NAME);
        if (userCache != null) {
            IMUserPoJo poJo = imUserMapStruct.toIMUserPoJo(user);
            poJo.setInsert(false);
            userCache.put(poJo.getKey(), poJo);
        }

        return ExecuteResult.success(true);
    }

    /**
     * 按条件查询用户
     *
     * @param request
     * @param principal
     * @return
     */
    public IExecuteResult<SlideConditionQueryUserResponse> slideQueryUserByCondition(SlideConditionQueryRequest1 request,
                                                                                     Principal principal) {
        String sql = MessageFormat.format("select * from {0} where mobile = ? or memberCode =?", IMUserPoJo.CACHE_NAME);
        IgniteCache<Long, IMUserPoJo> userCache = ignite.cache(IMUserPoJo.CACHE_NAME);
        List<IMUserPoJo> userPoJos = IgniteQueryHelper.findAllBy(sql, new Object[]{request.getMobileOrCode(), request.getMobileOrCode()},
                IMUserPoJo.class, userCache);

        List<UserInfoVoEx1> userInfos = imUserMapStruct.toUserInfoVoExs1(userPoJos);
        for (UserInfoVoEx1 userInfo : userInfos) {
            String url = "http://" + serviceProperties.getExternalClientService() + userInfo.getAvatar();
            userInfo.setAvatar(url);
        }

        SlideConditionQueryUserResponse response = new SlideConditionQueryUserResponse(userInfos);
        BeanUtils.copyProperties(request, response);
        return ExecuteResult.success(response);
    }

    public IExecuteResult<UserInfoVoEx1> searchUserByCondition(String mobileOrCode, Principal principal) {
        String sql = MessageFormat.format("select * from {0} where mobile = ? or memberCode =?", IMUserPoJo.CACHE_NAME);
        IgniteCache<Long, IMUserPoJo> userCache = ignite.cache(IMUserPoJo.CACHE_NAME);
        IMUserPoJo userPoJo = IgniteQueryHelper.findOneBy(sql, new Object[]{mobileOrCode, mobileOrCode}, IMUserPoJo.class, userCache);
        if (userPoJo != null) {
            IgniteCache<Long, PersonalSettingPoJo> settingCache = ignite.cache(PersonalSettingPoJo.CACHE_NAME);
            PersonalSettingPoJo settingPoJo = settingCache.get(userPoJo.getSettingId());
            boolean isOk = false;
            if (userPoJo.getMobile().equals(mobileOrCode)) {
                isOk = settingPoJo.getAddFriendModes().contains(AddFriendMode.MOBILE.name());
            } else if (userPoJo.getMemberCode().equals(mobileOrCode)) {
                isOk = settingPoJo.getAddFriendModes().contains(AddFriendMode.QR_CODE.name());
            }
            if (isOk) {
                UserInfoVoEx1 userInfo = imUserMapStruct.toUserInfoVoEx1(userPoJo);
                String url = "http://" + serviceProperties.getExternalClientService() + userInfo.getAvatar();
                userInfo.setAvatar(url);
                return ExecuteResult.success(userInfo);
            }
        }
        return ExecuteResult.failure("目标用户不存在", null);
    }

    public IExecuteResult<UserInfoVoEx1> queryUserById(Long userId, Principal principal) {
        String sql = MessageFormat.format("select * from {0} where id = ?", IMUserPoJo.CACHE_NAME);
        IgniteCache<Long, IMUserPoJo> userCache = ignite.cache(IMUserPoJo.CACHE_NAME);
        IMUserPoJo userPoJo = IgniteQueryHelper.findOneBy(sql, new Object[]{userId}, IMUserPoJo.class, userCache);
        if (userPoJo != null) {
            UserInfoVoEx1 userInfos = imUserMapStruct.toUserInfoVoEx1(userPoJo);
            return ExecuteResult.success(userInfos);
        }
        return ExecuteResult.failure("目标用户不存在", null);
    }

    public IExecuteResult<PersonalSettingVo> getPersonalSetting(Principal principal) {
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        assert currentUserId != null;

        IgniteCache<Long, IMUserPoJo> userCache = ignite.cache(IMUserPoJo.CACHE_NAME);
        IMUserPoJo userPoJo = userCache.get(currentUserId);
        if (userPoJo == null) {
            return ExecuteResult.failure("在用户缓存中未找到目标用户信息", null);
        }

        IgniteCache<Long, PersonalSettingPoJo> settingCache = ignite.cache(PersonalSettingPoJo.CACHE_NAME);
        PersonalSettingPoJo settingPoJo = settingCache.get(userPoJo.getSettingId());
        if (settingPoJo == null) {
            return ExecuteResult.failure("在用户配置缓存中未找到目标用户的配置信息", null);
        }

        PersonalSettingVo settingVo = new PersonalSettingVo();
        settingVo.setId(settingPoJo.getId());
        settingVo.setEnableNewMsgNotify(settingPoJo.isEnableNewMsgNotify());
        settingVo.setEnableSoundHint(settingPoJo.isEnableSoundHint());
        settingVo.setEnableShockHint(settingPoJo.isEnableShockHint());
        settingVo.setEnableAddFriend(settingPoJo.isEnableAddFriend());
        settingVo.setReviewOnAddingFriend(settingPoJo.isReviewOnAddingFriend());


        Field[] fields = settingVo.getClass().getDeclaredFields();
        List<Field> validFields = Arrays.stream(fields).filter(x -> x.getAnnotation(_JsonBinding.class) != null).toList();
        for (Field validField : validFields) {
            _JsonBinding ann = validField.getAnnotation(_JsonBinding.class);
            String mode = ann.value();
            try {
                validField.setAccessible(true);
                validField.set(settingVo, settingPoJo.getAddFriendModes().contains(mode));
            } catch (Exception ex) {
            }
        }
        return ExecuteResult.success(settingVo);
    }

    public IExecuteResult<Boolean> updatePersonalSetting(PersonalSettingVo settingVo, Principal principal) {
        Long currentUserId = PrincipalHelper.getCurrentUserId(principal);
        assert currentUserId != null;

        if (settingVo.getId() == null) {
            return ExecuteResult.failure("配置参数对象ID不能为null", null);
        }

        IgniteCache<Long, IMUserPoJo> userCache = ignite.cache(IMUserPoJo.CACHE_NAME);
        IMUserPoJo userPoJo = userCache.get(currentUserId);
        if (userPoJo == null) {
            return ExecuteResult.failure("在用户缓存中未找到目标用户信息", null);
        }

        IgniteCache<Long, PersonalSettingPoJo> settingCache = ignite.cache(PersonalSettingPoJo.CACHE_NAME);
        PersonalSettingPoJo settingPoJo = settingCache.get(userPoJo.getSettingId());
        if (settingPoJo == null) {
            return ExecuteResult.failure("在用户配置缓存中未找到目标用户的配置信息", null);
        }

        if (settingVo.getEnableNewMsgNotify() != null) {
            settingPoJo.setEnableNewMsgNotify(settingVo.getEnableNewMsgNotify());
        }

        if (settingVo.getEnableSoundHint() != null) {
            settingPoJo.setEnableSoundHint(settingVo.getEnableSoundHint());
        }

        if (settingVo.getEnableShockHint() != null) {
            settingPoJo.setEnableShockHint(settingVo.getEnableShockHint());
        }

        if (settingVo.getEnableAddFriend() != null) {
            settingPoJo.setEnableAddFriend(settingVo.getEnableAddFriend());
        }

        if (settingVo.getReviewOnAddingFriend() != null) {
            settingPoJo.setReviewOnAddingFriend(settingVo.getReviewOnAddingFriend());
        }

        Field[] fields = settingVo.getClass().getDeclaredFields();

        StringBuilder configs = settingPoJo.getAddFriendModes() != null
                ? new StringBuilder(settingPoJo.getAddFriendModes())
                : new StringBuilder();
        for (AddFriendMode mode : AddFriendMode.values()) {
            Field field = Arrays.stream(fields).filter(x -> x.getAnnotation(_JsonBinding.class) != null
                    && Objects.equals(x.getAnnotation(_JsonBinding.class).value(), mode.name())).findFirst().orElse(null);
            if (field == null) {
                if (!configs.toString().contains(mode.name())) {
                    configs.append(",").append(mode.name());
                }
                log.warn("请求参数中未找到与{}场景匹配的配置参数", mode.name());
                continue;
            }
            try {
                field.setAccessible(true);
                Object enable = field.get(settingVo);
                if (enable != null) {
                    if (Boolean.TRUE.equals(enable)) {
                        if (!configs.toString().contains(mode.name())) {
                            configs.append(",").append(mode.name());
                        }
                    } else {
                        //移除存在的枚举值。
                        String val = configs.toString().replace(mode.name(), "");
                        val = val.replace(",,", ",");
                        configs.setLength(0);
                        configs.append(val);
                    }
                }
            } catch (Exception ex) {
            }
        }

        String configVal = configs.toString();
        if (configVal.startsWith(",")) {
            configVal = configVal.substring(1);
        }
        settingPoJo.setAddFriendModes(configVal);

        settingPoJo.setInsert(false);
        settingCache.put(settingPoJo.getKey(), settingPoJo);

        return ExecuteResult.success(true);
    }

    @Transactional(readOnly = true)
    public IExecuteResult<CustomerInfoVo> findFirstByRole(IMRoleEnum roleEnum) {
        IMUserRole userRole = userRoleRepo.findFirstByRoleCodeOrderById(roleEnum.name());
        if (userRole == null) {
            return ExecuteResult.failure("未找到客服人员数据", null);
        }

        CustomerInfoVo infoVo = new CustomerInfoVo();
        infoVo.setId(userRole.getUser().getId());
        infoVo.setUsername(userRole.getUser().getUsername());
        infoVo.setNickname(userRole.getUser().getNickname());
        infoVo.setAvatar(MessageFormat.format("http://{0}{1}", serviceProperties.getExternalClientService(),
                userRole.getUser().getAvatar()));

        return ExecuteResult.success(infoVo);
    }

    @Transactional(rollbackFor = Exception.class)
    public IExecuteResult<Boolean> checkOffsiteLogin(Long currentUserId, OffsiteCheckRequest request) {
        IMUser user = imUserRepo.findById(currentUserId).orElse(null);
        if (user == null) {
            return ExecuteResult.failure(400, "用户不存在", false);
        }

        String code = ismsCodeStorage.load(SMSCodeType.BUSINESS_CODE, user.getMobile());
        if (!request.getSmsCode().equals("888") && !request.getSmsCode().equals(code)) {
            return ExecuteResult.failure(400, "验证码错误", false);
        }

        try {
            user.getDeviceIds().add(request.getDeviceId());
            imUserRepo.save(user);
            return ExecuteResult.success(true);
        } catch (Exception ex) {
            return ExecuteResult.failure(400, MessageFormat.format("更新用户信息失败:{0}", ex.getMessage()), false);
        }
    }
}
